import { Injectable } from '@nestjs/common';
import { PrismaService } from 'src/prisma/prisma.service';
import { CreateOrderDto } from './dto/create';
import { $Enums, OrderItem } from '@prisma/client';
import { getCurrentDate } from 'src/utils/date';

@Injectable()
export class OrdersService {
  constructor(private readonly prisma: PrismaService) {}

  async create(userId: number, dto: CreateOrderDto) {
    return this.prisma.$transaction(async (tx) => {
      const order = await this.prisma.order.create({
        data: {
          address: dto.address,
          count: dto.count,
          description: dto.description,
          user: { connect: { id: userId } },
          createdAt: getCurrentDate(),
        },
      });

      const items = await this.prisma.orderItem.createMany({
        data: dto.items.map((item) => ({
          orderId: order.id,
          menuItemId: item.id,
          quantity: item.quantity,
        })),
      });

      return items.count;
    });
  }

  async changeOrderStatus(orderId: number, status: $Enums.OrderStatus) {
    return this.prisma.order.update({
      where: { id: orderId },
      data: { status: status },
    });
  }

  async getAllOrders(status?: $Enums.OrderStatus) {
    return this.prisma.$transaction(async (tx) => {
      const orders = await this.prisma.order.findMany({
        where: { status },
        orderBy: { createdAt: 'desc' },
        include: { user: true },
      });

      return Promise.all(
        orders.map(async (order) => {
          const products = await this.prisma.orderItem.findMany({
            where: { orderId: order.id },
            include: {
              menuItem: true,
            },
          });

          return {
            ...order,
            productCount: products.length,
            sum: products.reduce(
              (acc, item) =>
                acc + item.menuItem.price.toNumber() * item.quantity,
              0,
            ),
          };
        }),
      );
    });
  }

  async getOrderByUserId(userId: number) {
    return this.prisma.$transaction(async (tx) => {
      const orders = await this.prisma.order.findMany({
        where: { user: { id: userId } },
        orderBy: { createdAt: 'desc' },
      });

      return Promise.all(
        orders.map(async (order) => {
          const products = await this.prisma.orderItem.findMany({
            where: { orderId: order.id },
            include: {
              menuItem: true,
            },
          });

          return {
            ...order,
            productCount: products.length,
            sum: products.reduce(
              (acc, item) =>
                acc + item.menuItem.price.toNumber() * item.quantity,
              0,
            ),
          };
        }),
      );
    });
  }

  async getOrderItems(orderId: number) {
    return this.prisma.$transaction(async (tx) => {
      const items = await this.prisma.orderItem.findMany({
        where: {
          orderId: orderId,
        },
        include: {
          menuItem: {
            select: {
              id: true,
              name: true,
              price: true,
              description: true,
            },
          },
        },
      });

      return items;
    });
  }
}
